<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>同花顺大单监控</title>  
    <style>  
        body {  
            background-color: #1C1D21; 
            margin: 0;  
            padding: 0px;  
            font-family: '微软雅黑', sans-serif;
            font-size: 14px;
        }  

        .container {  
            max-width: 1000px;  
            margin: 0 auto;  
            background-color: #1e1e1e;  
            padding: 0px;  
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);  
            border-radius: 8px;  
            overflow-x: auto;  
        }  

        .tabs {  
            display: flex;
            margin: 0px 0px 0px 5px;  
            justify-content: center; /* flex-end将内容靠右对齐 */
            align-items: center; /* 垂直居中对齐 */            
        }  

        .tabs span {  
            cursor: pointer;  
            padding: 2px 9px;  
            margin: 0;  
            background-color: #222222;  
            color: #e0e0e0;  
            width: 30px;
            transition: background-color 0.3s;  
        }  

        .tabs span:hover {
            background-color: #62669e; 
        }  
        .tabs .active {  
            background-color: #800000;  
        }  

        table {  
            width: 100%;  
            border-collapse: collapse;  
            margin-top: 0px;  
        }  

        table th {  
            background-color: #322;  
            color: #ddd;  
        }  

        th {  
            cursor: pointer;  
        }  

        th,  
        td {  
            padding: 0px;  
            border: 1px solid #333;  
            text-align: left;  
            position: relative;  
            white-space: nowrap;  
            overflow: hidden;  
            text-overflow: ellipsis;  
        }  

        th.sorted-asc::after,  
        th.sorted-desc::after {  
            content: '';  
            width: 0;  
            height: 0;  
            border-left: 5px solid transparent;  
            border-right: 5px solid transparent;  
            position: absolute;  
            right: 10px;  
        }  

        th.sorted-asc::after {  
            border-bottom: 5px solid red;  
            top: 50%;  
            transform: translateY(-50%);  
        }  

        th.sorted-desc::after {  
            border-top: 5px solid red;  
            top: 50%;  
            transform: translateY(-50%);  
        }  
        /*
        tr:nth-child(even) {  
            background-color: #1a1a1a;  
        }  
        */
        tr:hover {  
            background-color: #333;  
        }  

        .buy-row {  
            color: #F82947;  
        }  

        .sell-row {  
            color: #52ff52;  
        }  

        .summary-table {  
            width: 100%;  
            border-collapse: collapse;  
            margin-bottom: 0px;  
        }  

        .summary-table th,  
        .summary-table td {  
            color: #ddd;  
            border: 1px solid #333;  
            padding: 0px;  
            text-align: center;  
        }  

        .summary-table th {  
            background-color: #322;  
            color: white;  
        }  
  
        body::-webkit-scrollbar {  
            width: 0px;  
        }  

        body::-webkit-scrollbar-track {  
            background: #121212;  
        }  

        body::-webkit-scrollbar-thumb {  
            background: #555;  
            /*border-radius: 5px*/;  
        }  

        body::-webkit-scrollbar-thumb:hover {  
            background: #777;  
        }  

        .filter-dropdown {  
            margin-left: 10px;  
            padding: 2px;  
            border-radius: 4px;  
            background-color: #222;  
            color: #e0e0e0;  
            border: 1px solid #333;  
        }  

        .stock-title {  
            color: #ddd;  
        }  

        .data-summary {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .right-aligned {
            display: flex;
            justify-content: flex-end; /* 将内容靠右对齐 */
            align-items: center; /* 垂直居中对齐 */
            /* gap: 15px; /* 为每个子元素添加间距 */
        }

        .right-aligned span {
            color: #ddd;
            background-color: #423535;
            padding: 2px 5px; /* 添加内边距 */
        }

        .main-buy, .main-sell {
            color: red;
            background-color: #423535;
            width: 80px; 
            display: inline-block;
            text-align: right;             
        }

        .main-net {
            color: #52ff52;
            background-color: #423535;
            width: 80px; 
            display: inline-block;
            text-align: right; 
        }    
        .right-main {
            width: 50px;
            color: white;
            background-color: #5f0303;
            text-align: center;
        }        
        /* 隐藏清除图标 */
        input[type="time"]::-webkit-clear-button {
            display: none;
        }

        /* 设置背景为黑色，字体为白色 */
        #timePicker {
            margin-left: 10px;
            background-color: #1C1D21;;
            color: white;
            padding: 0px;
            border: 1px solid #683030;
            font-family: '微软雅黑', sans-serif;
            font-size: 14px;
        } 
        
        .custom-button {
            margin: 0; /* 调整按钮之间的间距 */            
            background-color: #2a2a2a;
            color: #fff;
            border: none;
            width: 60px;
            padding: 2px 5px;
            height: 25px;
            cursor: pointer;
        }        

    </style>  
    <!-- <script src="js/jquery.min.js"></script>   -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>  
</head>  

<body>  
    <div class="container">   
        <div class="data-summary">  
            <span class="stock-title"></span>
            <div class="right-aligned">
                <span class="right-main">净额</span><span class="main-net"></span>
                <span class="right-main">主买</span><span class="main-buy"></span>
                <span class="right-main">主卖</span><span class="main-sell"></span>
                <button class='custom-button' onclick='mainInstance.applyFilters(0, this);'>按单量</button>
                <button class='custom-button' onclick='mainInstance.applyFilters(1, this);'>按单额</button>
            </div>
        </div>          
        <div class="list">  
            <div>  
                <table class="summary-table">  
                    <thead>  
                        <tr>  
                            <th>主力大单分档</th>  
                            <th>买单</th>
                            <th>买额(万)</th>   
                            <th>卖单</th>  
                            <th>卖额(万)</th> 
                        </tr>  
                    </thead>  
                    <tbody>  

                    </tbody>  
                </table>  
                <div class="tabs">  
                    <span class="active">全部</span>  
                    <span>买单</span>  
                    <span>卖单</span>  
                    <span>9:30</span>  
                    <span>9:31</span>  
                    <span>9:32</span>
                    <span>9:33</span>
                    <span>9:34</span>
                    <span>9:35</span>  
                    <input type="time" id="timePicker" value="09:35" step="300">                 
                    <div id="filter"></div> 
                </div>                  
            </div>              
            <table>  
                <thead>  
                    <tr>  
                        <th data-key="ctime">成交时间</th>  
                        <th data-key="nature">大单性质</th>  
                        <th data-key="volume">成交量</th>  
                        <th data-key="value">金额</th>  
                        <th data-key="avgprice">价格</th>  
                    </tr>  
                </thead>  
                <tbody class="list_body">  

                </tbody>  
            </table>  
        </div>  
    </div>  
    <script>  
        class Main {  
            constructor() {               
                this.list = [];  
                this.title = {};
                this.currentIndex = 0;  
                this.sortKey = '';  
                this.sortOrder = 1;  
                this.filteredList = []; 
                this.lastMinutes = null; 
                this.typeId = 1; // 0:按主力单成交量分档 1:按主力单成交额分档
                this.updateButtonBackground();
                this.applyFilters(this.typeId); 
                this.init();  
                // 每隔3秒调用一次applyFilters
                setInterval(() => {
                    this.applyFilters(this.typeId);
                }, 3000);                
            }  

            updateButtonBackground() {
                const buttons = document.querySelectorAll('.custom-button');
                buttons.forEach((button, index) => {
                    if (index === this.typeId) {
                        button.style.backgroundColor = 'darkred'; 
                    } else {
                        button.style.backgroundColor = ''; 
                    }
                });
                const filterSpan = document.getElementById('filter');
                let selectHtml = '<select class="filter-dropdown" id="valueFilter">';

                if (this.typeId === 0) {
                    selectHtml += `
                        <option value="">全部数量</option>
                        <option value="500">0.5-1千手</option>
                        <option value="1000" selected>1-3千手</option>
                        <option value="3000">3-6千手</option>
                        <option value="6000">6千手</option>
                    `;
                } else if (this.typeId === 1) {
                    selectHtml += `
                        <option value="">全部金额</option>
                        <option value="1000000">100万</option>
                        <option value="3000000" selected>300万</option>
                        <option value="5000000">500万</option>
                        <option value="10000000">1000万</option>
                    `;
                }

                selectHtml += '</select>';
                filterSpan.innerHTML = selectHtml;  

                const filterDropdown = document.getElementById('valueFilter');
                filterDropdown.addEventListener('change', () => {  
                    this.applyFilters(this.typeId); 
                });                                
            }            

            async getListData() {  
                const stockInfo = this.getStockInfoFromUrl();  
                const stockCode = stockInfo.stockCode;  

                try {  
                    let res = await $.ajax({  
                        type: 'get',  
                        url: `http://vaserviece.10jqka.com.cn/Level2/index.php?&op=mainMonitorDetail&stockcode=${stockCode}`,  
                    });  
                    let result = JSON.parse(res);  
                    if (!result.list || !Array.isArray(result.list)) {  
                        console.error("Unexpected response format:", result);  
                        return;  
                    }  
                    result.list.forEach(item => {  
                        item.volume = parseFloat(item.volume.slice(0, -1));  
                    });  
                    this.list = result.list;  
                    this.title = result.title;
                } catch (error) {  
                    console.error("Error fetching stock data:", error);  
                }  
            }  

            getStockInfoFromUrl() {  
                const hash = window.location.hash;  

                if (hash && hash.startsWith('#')) {  
                    const stockCode = hash.substring(1);  
                    return { stockCode: stockCode, stockName: '' };  
                }  
                return { stockCode: '000001', stockName: '' };  
            }  

            init() {  
                const tabs = document.querySelectorAll('.tabs span');  
                const headers = document.querySelectorAll('th[data-key]');  
                const timePicker = document.getElementById('timePicker');  

                tabs.forEach((tab, i) => {  
                    tab.addEventListener('click', () => {  
                        tabs.forEach(t => t.classList.remove('active'));  
                        tab.classList.add('active');  
                        this.currentIndex = i;  
                        this.applyFilters(this.typeId); 
                    });  
                });  

                // 监听时间控件的 input 事件
                timePicker.addEventListener('input', (event) => {
                    const selectedTime = event.target.value;
                    const [hours, minutes] = selectedTime.split(':').map(Number);

                    // 计算最接近的5分钟间隔
                    const roundedMinutes = Math.round(minutes / 5) * 5;

                    // 确保分钟数在0-59之间
                    let finalMinutes = roundedMinutes % 60;
                    let finalHours = hours + Math.floor(roundedMinutes / 60);

                    // 特殊处理分钟从55变为0和从5变为0的情况
                    if (this.lastMinutes === 55 && finalMinutes === 0) {
                        finalHours += 1;
                    } else if (this.lastMinutes === 5 && finalMinutes === 0) {
                        finalHours -= 1;
                    }

                    // 确保小时数在9-15之间
                    if (finalHours > 15) {
                        finalHours = 9;
                    } else if (finalHours < 9) {
                        finalHours = 15;
                    }

                    // 格式化时间为HH:MM
                    const formattedTime = `${String(finalHours).padStart(2, '0')}:${String(finalMinutes).padStart(2, '0')}`;

                    // 更新输入框的值
                    timePicker.value = formattedTime;

                    // 更新上一次的分钟值
                    this.lastMinutes = minutes;
                    this.currentIndex = 9;

                    // 更新输入框的值
                    timePicker.value = formattedTime;

                    // 这里可以添加更多的逻辑，例如更新页面内容或发送请求
                    this.applyFilters(this.typeId);
                });

                headers.forEach(header => {  
                    header.addEventListener('click', () => {  
                        this.sortKey = header.getAttribute('data-key');  
                        this.sortOrder = this.sortOrder === 1 ? -1 : 1;  
                        this.sortAndDisplay();  
                        this.updateSortIndicators(header);  
                    });  
                });  
            }  

            applyFilters(n, button) {

                this.typeId = n;
                if (button) {
                    this.updateButtonBackground();
                } 

                const filterValue = document.getElementById('valueFilter').value;  
                const filterTime = document.getElementById('timePicker').value; 
                this.getListData();
                this.filteredList = this.currentIndex === 0
                    ? this.list
                    : this.list.filter(item => {
                        const timeMap = {
                            3: '09:30:00',
                            4: '09:31:00',
                            5: '09:32:00',
                            6: '09:33:00',
                            7: '09:34:00',
                            8: '09:35:00'
                        };

                        if (this.currentIndex in timeMap) {
                            return item.ctime <= timeMap[this.currentIndex];
                        } else {
                            return item.tradetype == this.currentIndex;
                        }
                    });

                if (filterTime && this.currentIndex === 9) {  
                    this.filteredList = this.list.filter(item => item.ctime <= filterTime);  
                }  

                if (filterValue) {  
                    this.filteredList = this.filteredList.filter(item => {
                        const valueToCompare = this.typeId === 0 ? item.volume : this.parseValue(item.value);
                        return valueToCompare >= parseFloat(filterValue);
                    });
                }  
                // 更新页面内容  
                this.updateStockTitle(this.title);  
                this.setDom(this.filteredList);  
                this.updateSummary(this.filteredList);  
            
            }  

            sortAndDisplay() {  
                const key = this.sortKey;  
                if (!key) return;  

                if (key === 'value') {  
                    this.filteredList.sort((a, b) => {  
                        const valueA = this.parseValue(a[key]);  
                        const valueB = this.parseValue(b[key]);  
                        return (valueA - valueB) * this.sortOrder;   
                    });  
                } else {  
                    this.filteredList.sort((a, b) => (a[key] > b[key] ? 1 : -1) * this.sortOrder);  
                }  

                this.setDom(this.filteredList);  
                this.updateSummary(this.filteredList);  
            }  

            updateSortIndicators(activeHeader) {  
                document.querySelectorAll('th').forEach(header => {  
                    header.classList.remove('sorted-asc', 'sorted-desc');  
                });  
                activeHeader.classList.add(this.sortOrder === 1 ? 'sorted-asc' : 'sorted-desc');  
            }  

            setDom(data) {  
                const list_body = document.querySelector('.list_body');  
                list_body.innerHTML = data.map(item => {  
                    let rowClass = '';  
                    if (item.nature.includes('买')) {  
                        rowClass = 'buy-row';  
                    } else if (item.nature.includes('卖')) {  
                        rowClass = 'sell-row';  
                    }  

                    return `  
                        <tr class="${rowClass}">  
                            <td>${item.ctime}</td>  
                            <td>${item.nature}</td>  
                            <td>${item.volume}手</td>  
                            <td>${item.value}</td>  
                            <td>${item.avgprice}</td>  
                        </tr>  
                    `;  
                }).join('');  
            }  

            updateSummary(data) {  
                const getSummaryStructure = (typeId) => {
                    if (typeId === 0) {
                        return {  
                            '>6000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '3000-6000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '1000-3000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '500-1000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 }  
                        };
                    } else if (typeId === 1) {
                        return {  
                            '>1000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '500-1000': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '300-500': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 },  
                            '100-300': { buy: 0, sell: 0, buyAmo: 0, sellAmo: 0 }  
                        };
                    }
                };

                const updateSummaryItem = (summary, key, item, value) => {
                    if (item.nature.includes('买')) {
                        summary[key].buy++;
                        summary[key].buyAmo += value;
                    } else {
                        summary[key].sell++;
                        summary[key].sellAmo += value;
                    }
                };

                const summary = getSummaryStructure(this.typeId);

                data.forEach(item => {  
                    const value = parseFloat(item.value.replace('万', ''));
                    if (this.typeId === 0) {
                        const volume = parseFloat(item.volume);
                        if (volume > 6000) updateSummaryItem(summary, '>6000', item, value);
                        else if (volume >= 3000) updateSummaryItem(summary, '3000-6000', item, value);
                        else if (volume >= 1000) updateSummaryItem(summary, '1000-3000', item, value);
                        else if (volume < 1000) updateSummaryItem(summary, '500-1000', item, value);
                    } else if (this.typeId === 1) {
                        if (value > 1000) updateSummaryItem(summary, '>1000', item, value);
                        else if (value >= 500) updateSummaryItem(summary, '500-1000', item, value);
                        else if (value >= 300) updateSummaryItem(summary, '300-500', item, value);
                        else if (value < 300) updateSummaryItem(summary, '100-300', item, value);
                    }
                });

                // 计算汇总值
                const totalBuyAmo = Object.values(summary).reduce((acc, curr) => acc + curr.buyAmo, 0);
                const totalSellAmo = Object.values(summary).reduce((acc, curr) => acc + curr.sellAmo, 0);  
                const netAmo = totalBuyAmo - totalSellAmo;           

                const summaryTableBody = document.querySelector('.summary-table tbody');  
                summaryTableBody.innerHTML = '';  // 清空表格内容

                const getTableRow = (key, label) => `
                    <tr>  
                        <td>${label}</td>  
                        <td style="color: red;">${summary[key].buy}笔</td>  
                        <td style="color: red;">${summary[key].buyAmo}</td> 
                        <td style="color: #52ff52;">${summary[key].sell}笔</td>
                        <td style="color: #52ff52;">${summary[key].sellAmo}</td>    
                    </tr>
                `;

                if (this.typeId === 0) {
                    summaryTableBody.innerHTML += [
                        getTableRow('>6000', '>6000手'),
                        getTableRow('3000-6000', '3000-6000手'),
                        getTableRow('1000-3000', '1000-3000手'),
                        getTableRow('500-1000', '500-1000手')
                    ].join('');
                } else if (this.typeId === 1) {
                    summaryTableBody.innerHTML += [
                        getTableRow('>1000', '>1000万'),
                        getTableRow('500-1000', '500-1000万'),
                        getTableRow('300-500', '300-500万'),
                        getTableRow('100-300', '100-300万')
                    ].join('');
                }

                this.updateMainDataDisplay(this.formatLargeNumber(totalBuyAmo * 10000), 
                                        this.formatLargeNumber(totalSellAmo * 10000), 
                                        this.formatLargeNumber(netAmo * 10000));  
            }

            updateStockTitle(titleData) {  
                const stockName = titleData.stockname || ''; // 默认名称   
                const stockTitleDiv = document.querySelector('.stock-title');  
                stockTitleDiv.textContent = `${stockName}`;  
            }  

            calculateNetVolume(mainBuy, mainSell) {  
                const buyValue = this.parseValue(mainBuy);  
                const sellValue = this.parseValue(mainSell);  
                const netVolume = buyValue - sellValue;  

                return this.formatLargeNumber(netVolume);  
            }  

            parseValue(valueWithUnit) {  
                const match = valueWithUnit.match(/(\d+(\.\d+)?)(万|亿)/);  
                if (match) {  
                    const value = parseFloat(match[1]);  
                    const unit = match[3];  
                    return value * (unit === '亿' ? 100000000 : 10000);  
                }  
                return 0;  
            }  

            formatLargeNumber(value) {  
                const absValue = Math.abs(value);  
                if (absValue >= 100000000) {  
                    return `${(value / 100000000).toFixed(2)}亿`;  
                } else {  
                    return `${(value / 10000).toFixed(2)}万`;  
                }  
            }  

            updateMainDataDisplay(mainBuy, mainSell, netVolume) {  
                const mainBuyElement = document.querySelector('.main-buy');  
                const mainSellElement = document.querySelector('.main-sell');  
                const mainNetElement = document.querySelector('.main-net');  

                mainBuyElement.textContent = mainBuy;  
                mainBuyElement.style.color = 'red';  
                mainSellElement.textContent = mainSell;  
                mainSellElement.style.color = '#52ff52';  

                const numericNetVolume = parseFloat(netVolume.replace(/[^\d.-]/g, ''));  

                mainNetElement.textContent = netVolume;  
                mainNetElement.style.color = numericNetVolume >= 0 ? 'red' : '#52ff52';  
            } 
           
        }  

        let mainInstance = new Main();  

        // 通达信版面插件加载或刷新后，自动获取股票信息并更新显示
        window.addEventListener('popstate', function(event) {
            mainInstance.applyFilters(mainInstance.typeId);
        });	

    </script>  
</body>  
</html>